package com.learner.ucenter.service.impl;

import com.learner.common.common.ConstValueEnum;
import com.learner.common.common.ResultEnum;
import com.learner.common.exception.ExceptionUtil;
import com.learner.common.exception.RestException;
import com.learner.common.redis.RedisUtils;
import com.learner.common.util.DateUtil;
import com.learner.common.util.FormUtils;
import com.learner.common.util.JwtInfo;
import com.learner.common.util.JwtUtils;
import com.learner.common.util.MD5;
import com.learner.pojo.trade.dto.MemberDto;
import com.learner.pojo.user.AccountPool;
import com.learner.pojo.user.GoodFriend;
import com.learner.pojo.user.User;
import com.learner.pojo.user.vo.DelFenZuRequestVo;
import com.learner.pojo.user.vo.EditFenZuRequestVo;
import com.learner.pojo.user.vo.LoginVo;
import com.learner.pojo.user.vo.ModifyFriendBeiZhuRequestVo;
import com.learner.pojo.user.vo.ModifyFriendFenZuRequestVo;
import com.learner.pojo.user.vo.MyFriendListResultVo;
import com.learner.pojo.user.vo.NewFenZuRequestVo;
import com.learner.pojo.user.vo.RegisterVo;
import com.learner.pojo.user.vo.SearchRequestVo;
import com.learner.pojo.user.vo.UpdateUserConfigureRequestVo;
import com.learner.pojo.user.vo.UpdateUserInfoRequestVo;
import com.learner.pojo.user.vo.UpdateUserPwdRequestVo;
import com.learner.ucenter.repository.AccountPoolDao;
import com.learner.ucenter.repository.UserDao;
import com.learner.ucenter.service.GoodFriendService;
import com.learner.ucenter.service.UserService;
import com.learner.ucenter.utils.ChatServerUtil;
import com.learner.ucenter.utils.VerifyCode;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.regex.Pattern;


/**
 * @Description: 会员登录注册的一个实现
 * @Author: ice2020x
 * @Date: 2021/10/24
 */
@Service
@Slf4j
public class UserServiceImpl implements UserService {


    @Autowired
    private UserDao userDao;

    @Autowired
    private AccountPoolDao accountPoolDao;

    @Autowired
    private MongoTemplate mongoTemplate;


    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private GoodFriendService goodFriendService;

    /**
     * @Description: 注册的业务
     * @Author: ice2020x
     * @Date: 2021/10/27
     */
    @Override
    public Map<String, Object> register(RegisterVo registerVo) {
        String code = registerVo.getCode();
        String nickname = registerVo.getNickname();
        String password = registerVo.getPassword();
        String mobile = registerVo.getMobile();
        if (StringUtils.isEmpty(mobile) || !FormUtils.isMobile(mobile)) {
            throw ExceptionUtil.createException(RestException.class, 1000001);
        }
        if (StringUtils.isEmpty(nickname) || StringUtils.isEmpty(password) || StringUtils.isEmpty(code)) {
            throw ExceptionUtil.createException(RestException.class, 1000002);
        }

        // 校验验证码
        String checkCode = RedisUtils.get(mobile);
        System.out.println(checkCode);
        if (!code.equals(checkCode)) {
            throw ExceptionUtil.createException(RestException.class, 1000003);
        }
        //  用户是否被注册
        User user = userDao.findUserByUsernameOrNickname(mobile, nickname);
        if (user != null) {
            throw ExceptionUtil.createException(RestException.class, 1000004);
        }
        //生成用户唯一标识账号code
        AccountPool accountPool = new AccountPool();
        //类型：用户
        accountPool.setType(ConstValueEnum.USERTYPE);
        //已使用状态
        accountPool.setStatus(ConstValueEnum.ACCOUNT_USED);
        accountPoolDao.save(accountPool);
        //密码加密
        String newPass = MD5.encrypt(registerVo.getPassword());
        User userInfo = new User();
        userInfo.setUsername(registerVo.getMobile());
        userInfo.setPassword(newPass);
        userInfo.setCode(String.valueOf(accountPool.getCode() + ConstValueEnum.INITIAL_NUMBER));
        //设置默认头像
        userInfo.setAvatar("https://chat-ice.oss-cn-beijing.aliyuncs.com/chat/9138f18c-1723-4d97-b027-c92c113bd707.jpg");
        userInfo.setNickname(nickname);
        userDao.save(userInfo);
        String id = userInfo.getId();
        userInfo.setUserId(id);
        user = userDao.save(userInfo);

        JwtInfo jwtInfo = new JwtInfo();
        jwtInfo.setUserId(userInfo.getId());
        jwtInfo.setNickname(nickname);
        jwtInfo.setUsername(userInfo.getUsername());
        jwtInfo.setAvatar(userInfo.getAvatar());
        String jwtToken = JwtUtils.getJwtToken(jwtInfo, 3600);

        Map<String, Object> result = new HashMap<>(2);
        result.put("token", jwtToken);
        result.put("userInfo", user);
        return result;
    }

    @Override
    public Map<String, Object> login(LoginVo loginVo) {
        // 获取验证码
        String verifyCode = RedisUtils.get("verifyCode");

        if (StringUtils.isEmpty(loginVo.getCode()) || !loginVo.getCode().equalsIgnoreCase(verifyCode)) {
            throw ExceptionUtil.createException(RestException.class, 1000005);
        }
        if (StringUtils.isEmpty(loginVo.getMobile()) || !FormUtils.isMobile(loginVo.getMobile())) {
            throw ExceptionUtil.createException(RestException.class, 1000001);
        }
        if (StringUtils.isEmpty(loginVo.getPassword())) {
            throw ExceptionUtil.createException(RestException.class, 1000002);
        }
        User user = userDao.findUserByUsername(loginVo.getMobile());
        if (user == null) {
            throw ExceptionUtil.createException(RestException.class, 1000006);
        }

        if (!MD5.encrypt(loginVo.getPassword()).equals(user.getPassword())) {
            throw ExceptionUtil.createException(RestException.class, 1000007);
        }

        if (user.getStatus() != 0) {
            throw ExceptionUtil.createException(RestException.class, 1000008);
        }

        JwtInfo jwtInfo = new JwtInfo();
        jwtInfo.setUserId(user.getId());
        jwtInfo.setNickname(user.getNickname());
        jwtInfo.setAvatar(user.getAvatar());
        jwtInfo.setUsername(user.getUsername());

        String jwtToken = JwtUtils.getJwtToken(jwtInfo, 3600 * 2);
        Map<String, Object> result = new HashMap<>(2);
        result.put("token", jwtToken);
        result.put("userInfo", user);
        return result;
    }

    @Override
    public MemberDto getMemberDtoIdByMemberId(String userId) {
        Optional<User> optional = userDao.findById(userId);
        if (!optional.isPresent()) {
            return null;
        }
        MemberDto memberDto = new MemberDto();
        BeanUtils.copyProperties(optional.get(), memberDto);
        return memberDto;
    }


    @Override
    public void getVerificationCode(HttpServletRequest request, HttpServletResponse response) {
        try {
            int width = 200;
            int height = 69;
            BufferedImage verifyImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

            //生成对应宽高的初始图片
            String randomText = VerifyCode.drawRandomText(width, height, verifyImg);
            //单独的一个类方法，出于代码复用考虑，进行了封装。
            //功能是生成验证码字符并加上噪点，干扰线，返回值为验证码字符
            RedisUtils.set("verifyCode", randomText, 10 * 60);
            // 必须设置响应内容类型为图片，否则前台不识别
            response.setContentType("image/jpeg");
            OutputStream os = response.getOutputStream();
            //输出图片流
            ImageIO.write(verifyImg, "png", os);
            os.flush();
            os.close();//关闭流
        } catch (IOException ignored) {
            log.error("生成验证码失败....");
        }
    }

    @Override
    public User getUserInfo(String userId, HttpServletRequest request) {
        User user = userDao.findById(userId).orElse(null);
        final String currentUserId = getUserId(request);
        if (user != null) {
            if (!StringUtils.isEmpty(currentUserId)) {
                final long count = mongoTemplate.count(new Query().addCriteria(Criteria.where("userM").is(currentUserId).and("userY").is(userId)), GoodFriend.class);
                user.setMyFriend(count > 0);
                final long count2 = mongoTemplate.count(new Query().addCriteria(Criteria.where("userY").is(currentUserId).and("userM").is(userId)), GoodFriend.class);
                user.setMyFriend(count2 > 0);
            }
            return user;
        }
        throw ExceptionUtil.createException(RestException.class, 1000010);
    }

    @Override
    public User getUserInfo(String userId) {
        return userDao.findById(userId).orElse(null);
    }

    //获取当前登录的用户uid
    private String getUserId(HttpServletRequest request) {
        JwtInfo infoByJwtToke = JwtUtils.getInfoByJwtToken(request);
        if (ObjectUtils.isEmpty(infoByJwtToke)) {
            return "";
        }
        final String userId = infoByJwtToke.getUserId();
        if (org.apache.commons.lang3.StringUtils.isBlank(userId)) {
            return "";
        }
        return userId;
    }

    @Override
    public void addNewFenZu(NewFenZuRequestVo requestVo) {
        try {
            User user = userDao.findById(requestVo.getUserId()).orElse(null);
            if (user == null) {
                throw ExceptionUtil.createException(RestException.class, 1000011);
            }
            Map<String, ArrayList<String>> friendFenZu = user.getFriendFenZu();
            if (!friendFenZu.containsKey(requestVo.getFenZuName())) {
                friendFenZu.put(requestVo.getFenZuName(), new ArrayList<>());
                Update update = new Update();
                update.set("friendFenZu", friendFenZu);
                Query query = new Query();
                query.addCriteria(Criteria.where("_id").is(new ObjectId(requestVo.getUserId())));
                mongoTemplate.findAndModify(query, update, User.class);
            }
        } catch (RuntimeException e) {
            log.error("添加分组失败", e);
            throw ExceptionUtil.createException(RestException.class, 1000012);
        }
    }


    @Override
    public void modifyFriendBeiZhu(ModifyFriendBeiZhuRequestVo requestVo, String userId) {
        User userInfo = userDao.findById(userId).orElse(null);
        if (userInfo == null) {
            throw ExceptionUtil.createException(RestException.class, 1000011);
        }
        Map<String, String> friendBeiZhuMap = userInfo.getFriendBeiZhu();
        friendBeiZhuMap.put(requestVo.getFriendId(), requestVo.getFriendBeiZhuName());
        //更新用户信息，查询条件
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(userId));
        Update update = new Update();
        update.set("friendBeiZhu", friendBeiZhuMap);
        mongoTemplate.findAndModify(query, update, User.class);

    }

    @Override
    public void modifyFriendFenZu(ModifyFriendFenZuRequestVo requestVo) {
        User userInfo = userDao.findById(requestVo.getUserId()).orElse(null);
        if (userInfo == null) {
            throw ExceptionUtil.createException(RestException.class, 1000011);
        }
        System.out.println("requestVo" + requestVo.getNewFenZuName());
        boolean flag = false;
        Map<String, ArrayList<String>> friendFenZu = userInfo.getFriendFenZu();
        for (Map.Entry<String, ArrayList<String>> entry : friendFenZu.entrySet()) {
            Iterator<String> iterator = entry.getValue().iterator();
            while (iterator.hasNext()) {
                if (iterator.next().equals(requestVo.getFriendId())) {
                    if (!entry.getKey().equals(requestVo.getNewFenZuName())) {
                        iterator.remove();
                        flag = true;
                        break;
                    }
                }
            }
            if (flag) {
                break;
            }
        }

        String newFenZuName = requestVo.getNewFenZuName();
        ArrayList<String> friendFenZuList = friendFenZu.get(newFenZuName);
        if (CollectionUtils.isEmpty(friendFenZuList)) {
            friendFenZuList = new ArrayList<>();
        }
        // 如果已经在这个分组了则不需要去管了
        if (!friendFenZuList.contains(requestVo.getFriendId())) {
            friendFenZuList.add(requestVo.getFriendId());
        }
        friendFenZu.put(newFenZuName, friendFenZuList);
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(requestVo.getUserId()));
        Update update = new Update();
        update.set("friendFenZu", friendFenZu);
        mongoTemplate.findAndModify(query, update, User.class);
    }

    //删除分组
    @Override
    public void deleteFenZu(DelFenZuRequestVo requestVo) {
        String userId = requestVo.getUserId();
        if (StringUtils.isEmpty(userId)) {
            throw ExceptionUtil.createException(RestException.class, 1000002);
        }
        User userInfo = userDao.findById(userId).orElse(null);
        if (userInfo == null) {
            throw ExceptionUtil.createException(RestException.class, 1000011);
        }
        Map<String, ArrayList<String>> friendFenZuMap = userInfo.getFriendFenZu();
        friendFenZuMap.remove(requestVo.getFenZuName());
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(requestVo.getUserId())));
        Update update = new Update();
        update.set("friendFenZu", friendFenZuMap);
        mongoTemplate.findAndModify(query, update, User.class);
    }

    @Override
    public void editFenZu(EditFenZuRequestVo requestVo) {
        User userInfo = userDao.findById(requestVo.getUserId()).orElse(null);
        if (userInfo == null) {
            throw ExceptionUtil.createException(RestException.class, 1000011);
        }
        Map<String, ArrayList<String>> friendFenZuMap = userInfo.getFriendFenZu();
        ArrayList<String> oldFenZuUsers = friendFenZuMap.get(requestVo.getOldFenZu());
        friendFenZuMap.remove(requestVo.getOldFenZu());
        friendFenZuMap.put(requestVo.getNewFenZu(), oldFenZuUsers);
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(requestVo.getUserId())));
        Update update = new Update();
        update.set("friendFenZu", friendFenZuMap);
        mongoTemplate.findAndModify(query, update, User.class);
    }

    //统计在线时长
    @Override
    public void updateOnlineTime(long onlineTime, String uid) {
        Update update = new Update();
        update.set("onlineTime", onlineTime);
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(uid)));
        mongoTemplate.upsert(query, update, User.class);
    }

    //更新用户的配置
    @Override
    public boolean updateUserConfigure(UpdateUserConfigureRequestVo requestVo, String uid) {
        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(uid)));
        Update update = new Update();
        update.set("opacity", requestVo.getOpacity())
                .set("blur", requestVo.getBlur())
                .set("notifySound", requestVo.getNotifySound())
                .set("bgColor", requestVo.getBgColor());
        return mongoTemplate.upsert(query, update, User.class).getModifiedCount() > 0;
    }

    @Override
    public void updateUserInfo(UpdateUserInfoRequestVo requestVo) {
        Map<String, Object> map = new HashMap<>();
        Integer code = null;
        String msg = null;
        Update update = new Update();
        boolean flag = false;
        switch (requestVo.getField()) {
            case "sex":
                String sexStr = requestVo.getValue().toString();
                if (!ChatServerUtil.isNumeric(sexStr)) {
                    throw ExceptionUtil.createException(RestException.class, 1000013);
                } else {
                    int sex = Integer.parseInt(sexStr);
                    if (sex != 0 && sex != 1 && sex != 3) {
                        throw ExceptionUtil.createException(RestException.class, 1000013);
                    }
                    update.set(requestVo.getField(), sex);
                }
                break;
            case "age":
                String age = requestVo.getValue().toString();
                if (!ChatServerUtil.isNumeric(age)) {
                    throw ExceptionUtil.createException(RestException.class, 1000014);
                }
                update.set(requestVo.getField(), Integer.valueOf(age));
                break;
            case "email":
                String email = (String) requestVo.getValue();
                if (!ChatServerUtil.isEmail(email)) {
                    throw ExceptionUtil.createException(RestException.class, 1000015);
                }
                update.set(requestVo.getField(), email);

                break;
            default:
                update.set(requestVo.getField(), requestVo.getValue());
                break;
        }

        Query query = new Query();
        query.addCriteria(Criteria.where("_id").is(new ObjectId(requestVo.getUserId())));
        UpdateResult upsert = mongoTemplate.upsert(query, update, User.class);

    }

    //修改密码
    @Override
    public void updateUserPwd(UpdateUserPwdRequestVo requestVo) {
        Map<String, Object> map = new HashMap<>();
        Integer code = null;
        String msg = null;
        //两次密码不一致
        if (!requestVo.getReNewPwd().equals(requestVo.getNewPwd())) {
            throw ExceptionUtil.createException(RestException.class, 1000016);
        } else {
            User userInfo = userDao.findById(requestVo.getUserId()).orElse(null);
            assert userInfo != null;
            //使用matches方法（参数1：不经过加密的密码，参数2：已加密密码）
            if (!bCryptPasswordEncoder.matches(requestVo.getOldPwd(), userInfo.getPassword())) {
                throw ExceptionUtil.createException(RestException.class, 1000017);
            } else {
                String bCryptNewPwd = bCryptPasswordEncoder.encode(requestVo.getNewPwd());
                //更新旧密码
                Update update = new Update();
                update.set("password", bCryptNewPwd);
                Query query = new Query();
                query.addCriteria(Criteria.where("_id").is(new ObjectId(requestVo.getUserId())));
                mongoTemplate.upsert(query, update, User.class);
                code = ResultEnum.SUCCESS.getCode();
                msg = "更新成功，请牢记你的新密码";
            }
        }
    }

    // 获取全部用户
    @Override
    public List<User> getUserList() {
        return userDao.findAll();
    }

    //根据注册时间获取用户
    @Override
    public List<User> getUsersBySignUpTime(String lt, String rt) {
        Query query = new Query();
        query.addCriteria(Criteria.where("signUpTime").gte(DateUtil.parseDate(lt, DateUtil.yyyy_MM))
                .lte(DateUtil.parseDate(rt, DateUtil.yyyy_MM)));
        return mongoTemplate.find(query, User.class);
    }

    //修改用户状态
    @Override
    public void changeUserStatus(String uid, Integer status) {
        Update update = new Update();
        update.set("status", status);
        Query query = new Query();
        query.addCriteria(Criteria.where("uid").is(uid));
        mongoTemplate.findAndModify(query, update, User.class);
    }

    //搜索用户
    @Override
    public HashMap<String, Object> searchUser(SearchRequestVo requestVo, String uid) {
        Query query = new Query();
        query.addCriteria(
                        Criteria.where(requestVo.getType()).regex(Pattern.compile("^.*" + requestVo.getSearchContent() + ".*$", Pattern.CASE_INSENSITIVE))
                                .and("_id").ne(uid)
                ).with(Sort.by(Sort.Direction.DESC, "_id"))
                .skip((long) (requestVo.getPageIndex() - 1) * requestVo.getPageSize())
                .limit(requestVo.getPageSize());
        Query query1 = new Query();

        query1.addCriteria(
                Criteria.where(requestVo.getType()).regex(Pattern.compile("^.*" + requestVo.getSearchContent() + ".*$", Pattern.CASE_INSENSITIVE))
                        .and("_id").ne(uid)
        );
        long count = mongoTemplate.count(query1, User.class);
        HashMap<String, Object> map = new HashMap<String, Object>(2);
        List<User> users = mongoTemplate.find(query, User.class);

        // 设置是不是我的朋友
        List<MyFriendListResultVo> myFriendsList = goodFriendService.getMyFriendsList(uid);
        for (MyFriendListResultVo myFriendListResultVo : myFriendsList) {
            for (User user : users) {
                if (myFriendListResultVo.getId().equals(user.getId())) {
                    user.setMyFriend(true);
                }
            }
        }

        map.put("total", count);
        map.put("list", users);
        return map;
    }
}
